#ifdef WIN32
#include <windows.h>
#endif

#include <iostream>
#include <GL/glew.h>
#include <btBulletCollisionCommon.h>

#include "mesh/Mesh.h"
#include "texture/TextureReference.h"

using namespace std;

Mesh::Mesh(vector<Vector3> vertices,
		vector<Vector3> vertexNormals,
		vector<Texture*> textures,
		vector<UVLayer*> uvLayers,
		vector<Material*> materials,
		vector<Face*> faces,
		ShaderProgram* program): Prototype() {

	// Initialize the display list to 0
	displayList = glGenLists(1);

	this->vertices = vertices;
	this->vertexNormals = vertexNormals;
	this->textures = textures;
	this->uvLayers = uvLayers;
	this->materials = materials;
	this->faces = faces;
	this->program = program;

	for (unsigned int i = 0; i < materials.size(); i++) {
		materials[i]->setShaderProgram(program);
	}
}

void Mesh::compile() {
	if (glIsList(displayList) == GL_TRUE)
		glDeleteLists(displayList, 1);

	glNewList(displayList, GL_COMPILE);

	program->use();
	GLint textures[3] = { 0, 1, 2 };
	GLint locTextures = glGetUniformLocation(program->getHandle(), "textures");
	glUniform1iv(locTextures, 3, textures);

	Material* currentMaterial = faces[0]->material;
	currentMaterial->use();
	glBegin(GL_TRIANGLES);

	for (unsigned int fIndex = 0; fIndex < faces.size(); fIndex++) {
		Face *face = faces[fIndex];
		if (face->material != currentMaterial) {
			glEnd();
			currentMaterial = face->material;
			currentMaterial->use();
			glBegin(GL_TRIANGLES);
		}

		for (unsigned int vIndex = 0; vIndex < face->vertices.size(); vIndex++) {
			vector<TextureReference*> texrefs = currentMaterial->getTexrefs();
			for(unsigned int t = 0; t < texrefs.size(); t++) {
				texrefs[t]->use(t, fIndex, vIndex);
			}

			if (face->vertexNormals.size() > 0) {
				Vector3 normal = vertexNormals[face->vertexNormals[vIndex]];
				glNormal3f(normal.x, normal.y, normal.z);
			}

			Vector3 vertex = vertices[face->vertices[vIndex]];
			glVertex3f(vertex.x, vertex.y, vertex.z);
		}

	}
	glEnd();
	glEndList();
}

void Mesh::draw() {
	glEnable(GL_CULL_FACE);
	glPolygonMode(GL_FRONT, GL_FILL);
	if (displayList)
	glCallList(displayList);
}

Mesh::~Mesh() {
	//cout << "Deleting Mesh " << name << "." << endl;
	for (unsigned int i = 0; i < uvLayers.size(); i++) {
		delete uvLayers[i];
	}
	for (unsigned int i = 0; i < faces.size(); i++) {
		delete faces[i];
	}

	glDeleteLists(displayList, 1);
}
